<?php
/**
 * @purpose
 * @Author: Madou
 * @Time  : 2022/8/6 17:20
 */

namespace App\Models\Task\SnapTasks\Repositories;

use App\Models\Task\SnapTasks\SnapTask;
use App\Models\Train\TrainSeat\Repositories\Interfaces\TrainSeatRepositoryInterface;
use App\Models\Train\TrainTripInfo\Repositories\Interfaces\TrainTripInfoRepositoryInterface;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
use JetBrains\PhpStorm\ArrayShape;

class SnapTaskTrips
{
    private SnapTask $task;

    public function __construct(SnapTask $task)
    {
        $this->task = $task;
    }

    public function getSnapTaskTripByIndex(string $trip_index): ?SnapTaskTrip
    {
        return collect($this->getTaskTrips())
            ->filter(fn(SnapTaskTrip $trip) => $trip->getTaskTripIndex() == $trip_index)->first();
    }

    #[ArrayShape([
        SnapTaskTrip::class,
    ])]
    public function getTaskTrips(bool $rebuild = false)
    {
        $trainSeatRepo     = app(TrainSeatRepositoryInterface::class);
        $trainTripInfoRepo = app(TrainTripInfoRepositoryInterface::class);
        $order_info        = $this->task->getTrainOrderInfo();
        $trains            = $order_info->getAlternativeTrains();
        $dates             = $order_info->getAlternativeTrainDates();
        $seats             = $order_info->getAlternativeSeats();
        $main_train        = $order_info->getMainTrain();
        $trips             = [];
        $cache_key         = "SnapTaskTrips:getTaskTrips:{$this->task->getTaskId()}";

        if (Cache::has($cache_key) && !$rebuild) {
            return Cache::get($cache_key);
        }
        $score = 0;
        foreach ($trains as $train_key => $train) {
            $train_code = $train['train_code'];
            $from_code  = $train['from_code'];
            $to_code    = $train['to_code'];
            $start_time = $train['start_time'];
            foreach ($dates as $date_key => $date) {
                foreach ($seats as $seat_key => $seat) {
                    $depart_at = Carbon::parse("{$date} {$start_time}")->format("Y-m-d H:i");
                    if ($train_code == $main_train->getTrainCode()
                        && $from_code == $main_train->getFromStationCode()
                        && $to_code == $main_train->getToStationCode()
                        && $seat == $order_info->getSeatName()
                        && $depart_at == Carbon::parse($main_train->getStartAt())->format("Y-m-d H:i")
                    ) {
                        continue;
                    }

                    $train_trip_info = $trainTripInfoRepo->findOneByTrainAndStation($train_code, $from_code, $to_code);
                    $train_seat      = $trainSeatRepo->findByTrainCodeAndSeatName($train_code, $from_code, $to_code, $seat);
                    if (!$train_seat) {
                        continue;
                    }

                    $score++;
                    $task_trip = new SnapTaskTrip($date, $train_trip_info, $train_seat);
                    $trips[]   = $task_trip;
                }
            }
        }
        Cache::put($cache_key, $trips, $this->getCacheTTL());
        return $trips;
    }

    public function getCacheTTL(): int
    {
        $stop_at = $this->getStopAt();

        return Carbon::now()->greaterThan($stop_at) ? 0 : Carbon::now()->diffInSeconds($stop_at);
    }

    public function getStopAt(): string
    {
        $stop_time   = $this->task->getStopTime();
        $order_info  = $this->task->getTrainOrderInfo();
        $trains      = $order_info->getAlternativeTrains();
        $dates       = $order_info->getAlternativeTrainDates();
        $main_train  = $order_info->getMainTrain();
        $arrive_at   = $main_train->getArriveAt();
        $arrive_time = Carbon::parse($arrive_at)->format('H:i');
        $date        = Carbon::parse($arrive_at)->toDateString();
        // 如果日期为空 取主行程的日期,否则取最大的日期
        if (!empty($dates)) {
            $date = max($dates);
        }

        // 如果选定的车次不为空 取车次的 到达时间和主行程到达时间中的最大值  否则 取主行程的到达时间
        if (!empty($trains)) {
            $times = collect($trains)->pluck('arrive_time')->toArray();
            $arrive_time && $times[] = $arrive_time;
            $arrive_time = max($times);
        }
        return Carbon::parse("{$date} {$arrive_time}")->subMinutes($stop_time)->toDateTimeString();
    }
}